﻿/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
**/
#include "shortcut.h"
#include "realizeshortcutwheel.h"
#include "ukcccommon.h"
using namespace ukcc;
#include <QDebug>

/* qt会将glib里的signals成员识别为宏，所以取消该宏
 * 后面如果用到signals时，使用Q_SIGNALS代替即可
 **/
#ifdef signals
#undef signals
#endif

#include <glib.h>
#include <glib/gi18n.h>

Shortcut::Shortcut() : mFirstLoad(true)
{
    pluginName = tr("Shortcut");
    pluginType = DEVICES;
    qRegisterMetaType<QStringPair>("QStringPair");
    qDBusRegisterMetaType<QStringPair>();
    qRegisterMetaType<QStringPairList>("QStringPairList");
    qDBusRegisterMetaType<QStringPairList>();

    qRegisterMetaType<KeyEntry>("KeyEntry");
    qDBusRegisterMetaType<KeyEntry>();
    qRegisterMetaType<KeyEntryList>("KeyEntryList");
    qDBusRegisterMetaType<KeyEntryList>();
}

Shortcut::~Shortcut()
{
    shortcutUi->deleteLater();
    shortcutUi = nullptr;
}

QString Shortcut::plugini18nName()
{
    return pluginName;
}

int Shortcut::pluginTypes()
{
    return pluginType;
}

QWidget *Shortcut::pluginUi()
{
    if (mFirstLoad) {
        mFirstLoad = false;
        shortcutUi = new ShortcutUi;
        shortcutInterface = new QDBusInterface("org.ukui.ukcc.session",
                                                "/Shortcut",
                                                "org.ukui.ukcc.session.Shortcut",
                                                QDBusConnection::sessionBus(), this);
        if (shortcutInterface->isValid()) { // 判断服务是否存在
            QDBusMessage message = shortcutInterface->call("ping"); // 判断dbus路径是否存在
            if (message.type() == QDBusMessage::ErrorMessage && message.errorMessage().contains("No such object path", Qt::CaseInsensitive)) {
                qWarning()<<shortcutInterface<<":"<<message.errorMessage();
            } else {
                QDBusConnection::sessionBus().connect("org.ukui.ukcc.session",
                                                      "/Shortcut",
                                                      "org.ukui.ukcc.session.Shortcut",
                                                      "changed",
                                                      this,
                                                      SLOT(dataChanged(QString)));
                initContent();
                connectUiSignals();
                connectToServer();
            }
        } else {
            qCritical() << "org.ukui.ukcc.session.Wallpaper DBus error:" << shortcutInterface->lastError();
        }
    }
    return shortcutUi;
}

const QString Shortcut::name() const
{
    return QStringLiteral("Shortcut");
}

bool Shortcut::isShowOnHomePage() const
{
    return false;
}

QIcon Shortcut::icon() const
{
    return QIcon::fromTheme("ukui-shortcut-key-symbolic");
}

bool Shortcut::isEnable() const
{
    return true;
}

void Shortcut::connectToServer()
{
    QThread *NetThread = new QThread;
    MThread *NetWorker = new MThread;
    NetWorker->moveToThread(NetThread);
    connect(NetThread, &QThread::started, NetWorker, &MThread::run);
    connect(NetWorker, &MThread::keychangedsignal,this,&Shortcut::shortcutChangedSlot);
    connect(NetThread, &QThread::finished, NetWorker, &MThread::deleteLater);
    NetThread->start();
}

void Shortcut::initContent()
{
    initShortEntry();
    initSystem();
    initCustom();
}

void Shortcut::initShortEntry()
{
    QDBusReply<KeyEntryList> listEntrySystem = shortcutInterface->call("getSystemShortcutEntry");
    QDBusReply<KeyEntryList> listEntryCustom = shortcutInterface->call("getCustomShortcutEntry");

    if (listEntrySystem.isValid()) {
        systemEntryList = listEntrySystem.value();
    }

    if (listEntryCustom.isValid()) {
        customEntryList = listEntryCustom.value();
    }
}

void Shortcut::initSystem()
{
    QDBusReply<QStringPairList> list = shortcutInterface->call("getSystemShortcut");
    if (list.isValid()) {
        for (QStringPair s : list.value()) {
            shortcutUi->addSystemShortcut(s.name, s.key, s.mediaKey, &systemEntryList, &customEntryList);
        }
    }
}

void Shortcut::initCustom()
{
    for (KeyEntry s : customEntryList) {
        shortcutUi->addCustomShortcut(s, &systemEntryList, &customEntryList);
    }
}

void Shortcut::connectUiSignals()
{
    connect(shortcutUi, &ShortcutUi::deleteShortcut, this, [=](QString path) {
        deleteCustomShortcut(path);
        shortcutInterface->call("updateShortcut");
    });

    connect(shortcutUi, &ShortcutUi::toCreateShortcut, this, [=](QString path, QString name, QString exec, QString key, bool buildFlag, bool convertFlag){
        createNewShortcut(path, name, exec, key, buildFlag, convertFlag);
        shortcutInterface->call("updateShortcut");
    });

    connect(shortcutUi, &ShortcutUi::updateSystemShortcut, this, [=](const QString &key, const QString &value){
        shortcutInterface->call("setSystemShortcut", key, value);
        shortcutInterface->call("updateShortcut");
    });

    connect(shortcutUi, &ShortcutUi::addButtonClicked, this, [=]{
        AddShortcutDialog *addDialog = new AddShortcutDialog(&systemEntryList, &customEntryList);
        addDialog->setTitleText(QObject::tr("Customize Shortcut"));

        connect(addDialog, &AddShortcutDialog::shortcutInfoSignal,
                [=](QString path, QString name, QString exec, QString key){
            createNewShortcut(path, name, exec, key, true, true);
            shortcutInterface->call("updateShortcut");
        });
        UkccCommon::buriedSettings(this->name(), QString("AddBtn"), QString("clicked"));
        addDialog->exec();
    });
}

void Shortcut::deleteCustomShortcut(QString path)
{
    if (path.isEmpty()) {
        return;
    }
    QProcess p(0);
    QStringList args;

    char *fullpath = path.toLatin1().data();
    QString cmd = "dconf";

    args.append("reset");
    args.append("-f");
    args.append(fullpath);
    p.execute(cmd, args);// command是要执行的命令,args是参数
    qDebug()<<"wait for finish";
    p.waitForFinished(-1);
    qDebug()<<QString::fromLocal8Bit(p.readAllStandardError());
}

void Shortcut::createNewShortcut(QString path, QString name, QString exec, QString key, bool buildFlag, bool convertFlag)
{
    if (key.contains("Meta")) {
        key.replace("Meta", "Win");
    }
    if (key.contains("Print")) {
        key.replace("Print", "PrtSc");
    }
    if (key.contains("Prtsc")) {
        key.replace("Prtsc", "PrtSc");
    }
    qDebug() << "createNewShortcut" << path << name << exec << key;
    QString availablepath;
    if (path.isEmpty()) {
        availablepath = findFreePath(); // 创建快捷键

        // 更新数据
        KeyEntry nKeyentry;
        nKeyentry.gsPath = availablepath;
        nKeyentry.nameStr = name;
        if (convertFlag == true) {
            nKeyentry.bindingStr = keyToLib(key);
        } else {
            nKeyentry.bindingStr = key;
        }
        nKeyentry.actionStr = exec;

        customEntryList.append(nKeyentry);
        if (true == buildFlag) {
            shortcutUi->addCustomShortcut(nKeyentry, &systemEntryList, &customEntryList);
        }
    } else {
        availablepath = path; // 更新快捷键

        if (convertFlag) {
            UkccCommon::buriedSettings(name, exec, QString("settings"), key);
        }
        // 更新数据
        for (int i = 0; i < customEntryList.count(); i++) {
            if (customEntryList[i].gsPath == availablepath) {
                customEntryList[i].nameStr = name;
                customEntryList[i].actionStr = exec;
                if (convertFlag == true) {
                    customEntryList[i].bindingStr = keyToLib(key);
                } else {
                    customEntryList[i].bindingStr = key;
                }
                break;
            }
        }
    }

    const QByteArray id(KEYBINDINGS_CUSTOM_SCHEMA);
    const QByteArray idd(availablepath.toLatin1().data());
    QGSettings *settings = new QGSettings(id, idd, this);
    if (convertFlag == true) {
         settings->set(BINDING_KEY, keyToLib(key));
    } else {
         settings->set(BINDING_KEY, key);
    }

    settings->set(NAME_KEY, name);
    settings->set(ACTION_KEY, exec);

    delete settings;
    settings = nullptr;
}

QString Shortcut::keyToLib(QString key)
{
    if (key.contains("Meta")) {
        key.replace("Meta", "Win");
    }

    if (key.contains("Start")) {
        key.replace("Start", "Win");
    }

    if (key.contains("Print", Qt::CaseInsensitive)) {
        key.replace("Print", "PrtSc", Qt::CaseInsensitive);
    }

    if (key.contains("+")) {
        QStringList keys = key.split("+");
        if (keys.count() == 2) {
            QString lower = keys.at(1);
            QString keyToLib = "<" + keys.at(0) + ">" + lower.toLower();
            qDebug() << "count = 2,keyToLib = " << keyToLib;
            return keyToLib;
        } else if (keys.count() == 3) {
            QString lower = keys.at(2);
            QString keyToLib = "<" + keys.at(0) + ">" + "<" + keys.at(1) + ">" + lower.toLower();
            qDebug() << "count = 3,keyToLib = " << keyToLib;
            return keyToLib;
        } else if (keys.count() == 4) {
            QString lower = keys.at(3);
            QString keyToLib = "<" + keys.at(0) + ">" + "<" + keys.at(1) + ">" + "<" + keys.at(2) + ">" + lower.toLower();
            qDebug() << "count = 4,keyToLib = " << keyToLib;
            return keyToLib;
        }
    }
    qDebug() << "count = 1,keyToLib = " << key;
    return key;
}

void Shortcut::shortcutChangedSlot()
{
    qInfo() << "receive cloud service signal";
    shortcutUi->clearCustomShorcutFrame();
    initCustom();
}

